<?php

namespace app\common\service;

use Firebase\JWT\JWT;

use think\Exception;

class Token
{

    private $tokenKey = '2020';

    /**
     * 创建 token
     * @param array $data 自定义参数数组
     * @param integer $exp_time 必填 token过期时间 单位:秒 例子：7200=2小时
     * @param string $scopes 选填 token标识，请求接口的token
     * @return string
     */
    public function createToken($data = [], $exp_time = 0, $scopes = '')
    {

        //JWT标准规定的声明，但不是必须填写的；
        //iss: jwt签发者
        //sub: jwt所面向的用户
        //aud: 接收jwt的一方
        //exp: jwt的过期时间，过期时间必须要大于签发时间
        //nbf: 定义在什么时间之前，某个时间点后才能访问
        //iat: jwt的签发时间
        //jti: jwt的唯一身份标识，主要用来作为一次性token。
        //公用信息
        try {
            $key = $this->tokenKey;
            $time = time();
            //$token['iss']=''; // 签发者 可选
            //$token['aud']=''; // 接收该JWT的一方，可选
            $token['iat'] = $time; // 签发时间
            $token['nbf'] = $time; // (Not Before)：某个时间点后才能访问，比如设置time+30，表示当前时间30秒后才能使用
            if ($scopes) {
                $token['scopes'] = $scopes; // token标识，请求接口的token
            }
            if (!$exp_time) {
                $exp_time = 3600 * 24 * 7; // 默认7天过期
            }
            $token['exp'] = $time + $exp_time; // token过期时间
            if ($data) {
                $token['data'] = $data; // 自定义参数
            }

            $json = JWT::encode($token, $key);

            return [
                'code' => 1,
                'msg' => 'success',
                'data' => [
                    'expires' => $exp_time,
                    'token' => $json
                ]
            ];
        } catch (\Firebase\JWT\ExpiredException $e) {
            return ['code' => 104, 'msg' => $e->getMessage(), 'data' => ''];
        } catch (Exception $e) {
            return ['code' => 0, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    /**
     * 验证token是否有效,默认验证exp,nbf,iat时间
     * @param string $jwt 需要验证的token
     * @return string $msg 返回消息
     */
    public function checkToken($jwt)
    {
        $key = $this->tokenKey;

        try {
            JWT::$leeway = 60; // 当前时间减去60，把时间留点余地
            $decoded = JWT::decode($jwt, $key, ['HS256']); // HS256方式，这里要和签发的时候对应

            return [
                'code' => 1,
                'msg' => 'success',
                'data' => (array)$decoded
            ];

        } catch (\Firebase\JWT\SignatureInvalidException $e) {
            // 签名不正确
            return ['code' => 101, 'msg' => $e->getMessage(), 'data' => '签名不正确'];
        } catch (\Firebase\JWT\BeforeValidException $e) {
            // 签名在某个时间点之后才能用
            return ['code' => 102, 'msg' => $e->getMessage(), 'data' => '签名在某个时间点之后才能用'];
        } catch (\Firebase\JWT\ExpiredException $e) {
            // token过期
            return ['code' => 103, 'msg' => $e->getMessage(), 'data' => 'token过期'];
        } catch (Exception $e) {
            return ['code' => 0, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }
}